#pragma once
#include"logger.hpp"
#include<iostream>
#include<websocketpp/server.hpp> 
#include<websocketpp/config/asio_no_tls.hpp>
#include<unordered_map>

typedef  enum {UNLOGIN , LOGIN} ss_statu; 
typedef websocketpp::server<websocketpp::config::asio> wsserver_t; 

class session
{
private:
  uint64_t _ssid;
  int _uid; 
  ss_statu _statu; 
  wsserver_t::timer_ptr _tp;
public:
  session(uint64_t ssid):_ssid(ssid) {  DLOG("%p session 已创建",this);  }
  ~session(){ DLOG("%p session 已销毁",this); }
  
  void set_user(int uid) {   _uid = uid; }
  int get_user(){return _uid; }
  void set_statu(ss_statu statu){_statu = statu;}
  bool is_login(){return _statu == LOGIN; }
  void set_timer(const wsserver_t::timer_ptr& tp){ _tp = tp; }
  uint64_t ssid(){return _ssid;}
  wsserver_t::timer_ptr& get_timer(){return _tp;}

};

using session_ptr = std::shared_ptr<session>; 

#define SESSION_FOREVER -1
#define SESSION_TIMEOUT 30000

class session_manage
{
private:
  uint64_t _next_ssid; //下一个ssid 
  std::mutex _mutex; 
  wsserver_t *_ser; 
  std::unordered_map<uint64_t,session_ptr> _sessions;  //ssid 和 session之间的映射

public:
  session_manage(wsserver_t* ser):_next_ssid(1), _ser(ser){DLOG("session manage 创建成功");}
  ~session_manage(){DLOG("session manage 即将销毁");}

  session_ptr create_session(int uid , ss_statu statu){
    std::unique_lock<std::mutex> lock(_mutex); 
    session_ptr sp(new session(_next_ssid)); 
    sp->set_user(uid) ; 
    sp->set_statu(statu); 

    _sessions.insert(std::make_pair(_next_ssid,sp)); 
    _next_ssid++; 
    return sp;
  }

  session_ptr get_session_by_ssid(uint64_t ssid){
    std::unique_lock<std::mutex> lock(_mutex);
    auto it = _sessions.find(ssid); 
    if(it == _sessions.end())
    {
      //没找到 
      return session_ptr(); 
    }
    return it->second; 
  }
  
  //销毁session
  void remove_session(uint64_t ssid){
    std::unique_lock<std::mutex> lock(_mutex); 
    _sessions.erase(ssid);
  } 
  
  void append_session(const session_ptr& ssp)
  {
    std::unique_lock<std::mutex> lock(_mutex); 
    _sessions.insert(std::make_pair(ssp->ssid(),ssp));
  }

  //设置ssid对应sesson的超时时间
  void set_session_expire_time(uint64_t ssid , int ms)
  {
    //获取session对象 
    session_ptr ssp = get_session_by_ssid(ssid);

    if(ssp.get() == nullptr)
    {
      //session 不存在 
      return; 
    }

    wsserver_t::timer_ptr tp = ssp->get_timer();
    //1.session永久存在(没有设置定时任务)的情况下，设置永久存在
    if(tp.get() == nullptr && ms == SESSION_FOREVER)
    {
      return; 
    }
    //2.session永久存在情况下，设置定时 
    else if(tp.get() == nullptr && ms != SESSION_FOREVER)
    {
      //获取定时任务
      wsserver_t::timer_ptr tmp_tp = _ser->set_timer(ms,std::bind(&session_manage::remove_session,this,ssid)); 
      //设置定时任务  
      ssp->set_timer(tmp_tp);
    }
    //3.session设置定时的情况下，设置成永久存在
    else if(tp.get() != nullptr && ms == SESSION_FOREVER)
    {
      //先删除原有的定时任务
      tp->cancel(); 
      
      //session定时任务设置为空/永久存在 
      ssp->set_timer(wsserver_t::timer_ptr());

      //设置一个0毫秒的定时任务,防止在删除之前添加了备份的session
      _ser->set_timer(0,std::bind(&session_manage::append_session,this,ssp));
    }
    //4.session设置定时的情况下，重置定时任务时间 
    else if(tp.get() != nullptr && ms != SESSION_FOREVER)
    {
      //先删除 
      tp->cancel(); 

      //设置空任务 
      ssp->set_timer(wsserver_t::timer_ptr()); 
      
      //设置0毫秒任务
      _ser->set_timer(0,std::bind(&session_manage::append_session,this,ssp));

      //获取新的定时删除任务
      wsserver_t::timer_ptr tmp_tp = _ser->set_timer(ms,std::bind(&session_manage::remove_session,this,ssid));
      //设置新任务 
      ssp->set_timer(tmp_tp);
    }

  }


};
